﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="SqlSchemaInfo.cs" company="MyCoreLib">
//   Copyright (C) 2014 Alexey Evlampiev. All rights reserved.
// </copyright>
// <summary>
//   Selected database objects schema container.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

using System.Diagnostics;

namespace MyCoreLib.Automation.Data.SqlClient.Metadata
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;

    /// <summary>
    /// Selected database objects schema container.
    /// </summary>
    public class SqlSchemaInfo
    {
        #region Private Fields

        /// <summary>
        /// The load stored procedure full names task
        /// </summary>
        private readonly Task<string[]> m_loadStoredProcedureFullNamesTask;

        /// <summary>
        /// The load user table type full names task
        /// </summary>
        private readonly Task<string[]> m_loadUserTableTypeFullNamesTask;

        /// <summary>
        /// The load selected stored procedure metadata task
        /// </summary>
        private readonly Task<SqlStoredProcedureMetadataCollection> m_loadSelectedStoredProcedureMetadataTask;

        /// <summary>
        /// The database stored procedure full names lookup
        /// </summary>
        private HashSet<string> m_databaseStoredProcedureFullNamesLookup;

        /// <summary>
        /// The database stored procedure full names
        /// </summary>
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        private ReadOnlyCollection<string> m_databaseStoredProcedureFullNames;

        /// <summary>
        /// The database user table type full names
        /// </summary>
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        private ReadOnlyCollection<string> m_databaseUserTableTypeFullNames;

        /// <summary>
        /// The m_selected stored procedure metadata
        /// </summary>
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        private ReadOnlyCollection<SqlStoredProcedureMetadata> m_selectedStoredProcedureMetadata; 

        #endregion

        #region Constructors
        /// <summary>
        /// Initializes a new instance of the <see cref="SqlSchemaInfo"/> class.
        /// </summary>
        /// <param name="output">The output.</param>
        /// <param name="schemaReader">The schema reader.</param>
        /// <param name="selectedProcedureFullNames">The selected procedure full names.</param>
        /// <param name="token">The token.</param>
        /// <exception cref="System.ArgumentNullException">
        /// output
        /// or
        /// schemaReader
        /// </exception>
        public SqlSchemaInfo(
            IOutput output,
            ISqlSchemaReader schemaReader,
            IEnumerable<string> selectedProcedureFullNames,
            CancellationToken token)
        {
            if (ReferenceEquals(output, null))
            {
                throw new ArgumentNullException("output");
            }

            if (ReferenceEquals(schemaReader, null))
            {
                throw new ArgumentNullException("schemaReader");
            }

            selectedProcedureFullNames = (selectedProcedureFullNames ?? Enumerable.Empty<string>())
                .Where(s => !string.IsNullOrWhiteSpace(s))
                .Select(s => s.Trim())
                .ToList();

            var loadSqlClrTypeMetadataTask = schemaReader.LoadSqlClrTypeMetadataAsyn(token);
            var loadSqlUserableTypeMetadataTask = schemaReader.LoadSqlUserTableTypeMetadataAsyn(token);

            m_loadStoredProcedureFullNamesTask = schemaReader.LoadStoredProcedureFullNamesAsync(token);
            m_loadUserTableTypeFullNamesTask = schemaReader.LoadUserTableTypeFullNamesAsync(token);
            m_loadSelectedStoredProcedureMetadataTask = schemaReader.LoadSelectedStoredProcedureMetadataAsync(
                selectedProcedureFullNames,
                m_loadStoredProcedureFullNamesTask,
                loadSqlClrTypeMetadataTask,
                loadSqlUserableTypeMetadataTask,
                token);
        } 

        #endregion

        /// <summary>
        /// Gets the database stored procedure full names.
        /// </summary>
        /// <value>
        /// The database stored procedure full names.
        /// </value>
        public ReadOnlyCollection<string> DatabaseStoredProcedureFullNames
        {
            get
            {
                return m_databaseStoredProcedureFullNames ??
                       (m_databaseStoredProcedureFullNames =
                           new ReadOnlyCollection<string>(m_loadStoredProcedureFullNamesTask
                               .GetAwaiter()
                               .GetResult()
                               .ToList()));
            }
        }

        /// <summary>
        /// Gets the database user table type full names.
        /// </summary>
        /// <value>
        /// The database user table type full names.
        /// </value>
        public ReadOnlyCollection<string> DatabaseUserTableTypeFullNames
        {
            get
            {
                return m_databaseUserTableTypeFullNames ??
                    (m_databaseUserTableTypeFullNames =
                           new ReadOnlyCollection<string>(m_loadUserTableTypeFullNamesTask
                               .GetAwaiter()
                               .GetResult()
                               .ToList()));
            }
        }

        /// <summary>
        /// Gets the selected stored procedure metadata.
        /// </summary>
        /// <value>
        /// The selected stored procedure metadata.
        /// </value>
        public ReadOnlyCollection<SqlStoredProcedureMetadata> SelectedStoredProcedureMetadata
        {
            get
            {
                return m_selectedStoredProcedureMetadata ?? 
                    (m_selectedStoredProcedureMetadata = 
                    new ReadOnlyCollection<SqlStoredProcedureMetadata>(m_loadSelectedStoredProcedureMetadataTask
                        .GetAwaiter()
                        .GetResult()));                 
            }
        }

        /// <summary>
        /// Checks whether the specified stored procedure exists in the database.
        /// </summary>
        /// <param name="storedProcedureFullName">Full name of the stored procedure.</param>
        /// <returns>True if the procedure exists in the database and False otherwise.</returns>
        public bool StoredProcedureExists(string storedProcedureFullName)
        {
            var lookup = m_databaseStoredProcedureFullNamesLookup ??
                         (m_databaseStoredProcedureFullNamesLookup =
                             new HashSet<string>(
                                 m_loadStoredProcedureFullNamesTask
                                     .GetAwaiter()
                                     .GetResult()
                                     .ToList(), 
                                 StringComparer.OrdinalIgnoreCase));
            return lookup.Contains(storedProcedureFullName);
        }
    }
}
